#include "stm32f4xx.h"
#include "board.h"
#include "ds18b20.h"
#include "delay.h"
#include "drv_1wire.h"


#ifdef RT_USING_FINSH
#include <finsh.h>
#endif

struct rt_device          ds18b20_device;


/**
  * @brief  This is a ds18b20 reset function.
  * @param  None
  * @retval None
  */
static void ds18b20_rest(void)
{
    ONEWIRE_IO_OUT();   /* 设置输出模式*/
    ONEWIRE_DQ_OUT = 0; /* 拉低DQ*/
    delay_us(750);      /* 持续750us*/
    ONEWIRE_DQ_OUT = 1; /* 拉高DQ*/
    delay_us(15);        /* 持续15us*/
}
/**
  * @brief  This is a Wait ds18b20 stable  function.
  * @param  None
  * @retval None
  */
static uint8_t ds18b20_wait_stable(void)
{
    uint8_t val = 0;
    ONEWIRE_IO_IN();
    while (ONEWIRE_DQ_IN && val < 200)
    {
        val++;
        delay_us(10);
    };
    if (val >= 200)
        return 1;
    else
        val = 0;
    while (!ONEWIRE_DQ_IN && val < 240) /* ds18b20稳定后 返回1*/
    {
        val++;
        delay_us(1);
    };
    if (val >= 240)
        return 1;
    return 0;
}
/**
  * @brief  The function of this function is to read ds18b20 bytes.
  * @param  None
  * @retval The bytes read
  */
static uint8_t ds18b20_read_byte(void)
{
    uint8_t i;
    uint8_t data_bit = 0;
    uint8_t data_byte = 0;
    for (i = 1; i <= 8; i++)
    {
        ONEWIRE_IO_OUT();
        ONEWIRE_DQ_OUT = 0;
        delay_us(2);
        ONEWIRE_DQ_OUT = 1;
        ONEWIRE_IO_IN();
        delay_us(12);
        if (ONEWIRE_DQ_IN)
            data_bit = 1;
        else
            data_bit = 0;
        delay_us(50);

        /* 将读取的字节合并成一个字节*/
        data_byte = (data_bit << 7) | (data_byte >> 1);
        data_bit = 0;
    }
    return data_byte;
}
/**
  * @brief  The function of this function is to write a byte to the ds18b20.
  * @param  Write byte
  * @retval None
  */
static void ds18b20_write_byte(uint8_t dat)
{
    uint8_t j;
    uint8_t testb;
    ONEWIRE_IO_OUT();
    for (j = 1; j <= 8; j++)
    {
        testb = dat & 0x01;
        dat = dat >> 1;
        if (testb)
        {
            ONEWIRE_DQ_OUT = 0;
            delay_us(2);
            ONEWIRE_DQ_OUT = 1;
            delay_us(60);
        }
        else
        {
            ONEWIRE_DQ_OUT = 0;
            delay_us(60);
            ONEWIRE_DQ_OUT = 1;
            delay_us(2);
        }
    }
}
/**
  * @brief  This function is used to start ds18b20.
  * @param  None
  * @retval None
  */
static void ds18b20_start(void)
{
    ds18b20_rest();
    if (!ds18b20_wait_stable())
    {
        ds18b20_write_byte(SKIP_Rom);
        ds18b20_write_byte(CONVERT_START);
    }
    else
    {
        rt_kprintf("> DS18B20 does not exist!\r\n");
    }
}
/**
  * @brief  This function is used to get the temperature.
  * @param  None
  * @retval None
  */
static rt_size_t ds18b20_gettemp(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
{
    int8_t temp;
    uint8_t TL, TH;
    short *tem = RT_NULL;
    tem = (short *)buffer;
    ds18b20_start();       /* 启动*/
    ds18b20_rest();
    ds18b20_wait_stable(); /* 等待ds18b20稳定*/
    ds18b20_write_byte(SKIP_Rom);
    ds18b20_write_byte(SCRATCHPAD);
    TL = ds18b20_read_byte(); /* LSB*/
    TH = ds18b20_read_byte(); /* MSB*/

    if (TH > 7)   /* 表明最高位为1*/
    {
        TH = ~TH;
        TL = ~TL;
        temp = 0; /* 温度为负数*/
    }
    else
        temp = 1; /* 温度为正数*/
    *tem = TH;    /* 获取高8位*/
    *tem <<= 8;
    *tem += TL;   /* 获取低8位*/
    *tem = *tem * 0.625;
    if (temp)
        return (rt_size_t) * tem; /* 返回温度值*/
    else
        return (rt_size_t) - *tem;
}
static rt_err_t rt_ds18b20_open(rt_device_t dev, rt_uint16_t oflag)
{
    return RT_EOK;
}
int rt_hw_ds18b20_init()
{
    ds18b20_device.type         = RT_Device_Class_Miscellaneous;
    ds18b20_device.rx_indicate  = RT_NULL;
    ds18b20_device.tx_complete  = RT_NULL;

    ds18b20_device.init         = RT_NULL;
    ds18b20_device.open         = rt_ds18b20_open;
    ds18b20_device.close        = RT_NULL;
    ds18b20_device.read         = ds18b20_gettemp;
    ds18b20_device.write        = RT_NULL;
    ds18b20_device.control      = RT_NULL;

    ds18b20_device.user_data    = RT_NULL;
    /* register a character device */
    rt_device_register(&ds18b20_device, "ds18b20", RT_DEVICE_FLAG_RDONLY);

    return 0;
}
INIT_BOARD_EXPORT(rt_hw_ds18b20_init);

/* RT-Thread Hardware PIN APIs */
void rt_ds18b20_read(void)
{
    float val = 0;
    uint8_t  integer = 0;
    uint8_t  decimal = 0;

    integer = ds18b20_gettemp(RT_NULL, RT_NULL, &val, 1) / 10;
    decimal = ds18b20_gettemp(RT_NULL, RT_NULL, &val, 1) % 10;
    if (85 == integer)
    {
        rt_kprintf("> Get The Temperate ing，Please wait a moment.... \r\n");
        delay_ms(1000);
        integer = ds18b20_gettemp(RT_NULL, RT_NULL, &val, 1) / 10;
        decimal = ds18b20_gettemp(RT_NULL, RT_NULL, &val, 1) % 10;
        rt_kprintf("> Temperate: %d.%d℃ \r\n", integer, decimal);
    }
    else
    {
        rt_kprintf("> Temperate: %d.%d℃ \r\n", integer, decimal);
    }

    return ;
}
FINSH_FUNCTION_EXPORT_ALIAS(rt_ds18b20_read, gettemp, Fetch current temperature);

//rt_device_t rt_ds18b20_set_device(const char *name)
//{
//    rt_device_t new;

//    /* find new console device */
//    new = rt_device_find(name);
//    if (new != RT_NULL)
//    {
//        /* set new console device */
//        rt_device_open(new, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_STREAM);
//    }
//    return new;
//}

//int rt_hw_ds18b20_init()
//{
//    rt_ds18b20_set_device("ds18b20");
//    return 0;
//}
//INIT_BOARD_EXPORT(rt_hw_ds18b20_init);